/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package magnata;


import java.util.ArrayList;
import java.util.Observable;
import java.util.StringTokenizer;


public class Magnata extends Observable {
   
    private Deck m_deck;
    private Dice m_dice;
    private DiscardPile m_discardPile;
    private Table m_table;
    private ArrayList<Player> m_players;
    private TempPile m_tempPile;
    private States.State m_state;
    private StateMachine m_statemachine;
    private StringTokenizer m_tk;
    private Player m_currentPlayer;

    public Magnata() {
        m_deck = new Deck();
        m_table = new Table();
        m_players = new ArrayList<>();
        m_tempPile = new TempPile();
        m_discardPile = new DiscardPile();
        m_dice = new Dice();
        
        m_statemachine = new StateMachine(this);
        
    }

// <editor-fold defaultstate="Getters" desc="Getters from the variables">
   
    public Player getCurrentPlayer()
    {
        return m_currentPlayer;
    }
    
    public DiscardPile getDiscardPile()
    {
        return m_discardPile;
    }
    
    public Deck getDeck()
    {
        return m_deck;
    }
    
    public Table getTable()
    {
        return m_table;
    }
    
    public Dice getDice()
    {
        return m_dice;
    }
    
    public ArrayList<Player> getPlayers()
    {
        return m_players;
    }
    
    public TempPile getTempPile()
    {
        return m_tempPile;
    }
    
    public StateMachine getStateMachine()
    {
        return m_statemachine;
    }
    
//</editor-fold>
    
    public void setupGame()
    {
       m_statemachine.setupGame(); //Faz o setup
       m_currentPlayer = m_players.get(0);
    }
    
    public void nexTurn()
    {
        if(m_currentPlayer.equals(m_players.get(0)))
            m_currentPlayer = m_players.get(1);
        else
            m_currentPlayer = m_players.get(0);
    }
    
    public int getGameState()
    {
        return m_statemachine.getGameState();
    }
    
   

//    /*
//     * Para todas as fun��oes de exec em seguida, o processo principal faz-se atrav��s
//     * de um stringtokenizer... tendo como limitador default o espa��o
//     * 1�� compara-se com o numero de tokens que a string tem
//     * de seguida compara-se o comando com o que �� preciso para executar o resto da fun����o
//     * para os casos que seja preciso introduzir um numero como parametro �� criada a fun����o
//     * matchesInt(pos) -> sendo pos o ultimo token do stringtokenizer;
//     */
//    private boolean exec_command_placeCardOnTable(String command) {
//        m_tk = new StringTokenizer(command);
//        String text;
//
//
//        if (m_tk.countTokens() == 3) {
//            text = m_tk.nextToken();
//            text += " ";
//            text += m_tk.nextToken();
//
//            String pos = m_tk.nextToken().trim();
//
//
//
//            if (text.equalsIgnoreCase("place card")) {
//
//                if (matchesInt(pos)) {
//                    m_game.placeCardOnTable(Integer.parseInt(pos));
//                    return true;
//                } else {
//                    m_consola.writeTextNL("O parametro da pos nao e um inteiro");
//                    return true;
//                }
//
//            }
//        }
//
//        return false;
//    }
//
//    private boolean exec_command_discardCard(String command) {
//        m_tk = new StringTokenizer(command);
//        String text;
//
//
//        if (m_tk.countTokens() == 3) {
//            text = m_tk.nextToken();
//            text += " ";
//            text += m_tk.nextToken();
//
//            String pos = m_tk.nextToken().trim();
//
//            if (text.equalsIgnoreCase("discard card")) {
//
//                if (matchesInt(pos)) {
//                    m_game.discardCard(Integer.parseInt(pos));
//                    return true;
//                } else {
//                    m_consola.writeTextNL("O parametro da pos nao e um inteiro");
//                    return true;
//                }
//            }
//        }
//
//        return false;
//    }
//
//    private boolean exec_command_help(String command) {
//        m_tk = new StringTokenizer(command);
//        String text;
//
//
//        if (m_tk.countTokens() == 1) {
//            text = m_tk.nextToken().trim();
//
//            if (text.equalsIgnoreCase("help")) {
//                m_consola.writeTextNL(m_game.help());
//                return true;
//            }
//        }
//
//        return false;
//    }
//
//    private boolean exec_command_getCardFromDeck(String command) {
//        m_tk = new StringTokenizer(command);
//        String text;
//
//
//        if (m_tk.countTokens() == 2) {
//            text = m_tk.nextToken();
//            text += " ";
//            text += m_tk.nextToken();
//
//            if (text.equalsIgnoreCase("draw card")) {
//                m_game.getCardFromDeck();
//                return true;
//            }
//        }
//
//        return false;
//    }
//
//    private boolean exec_command_Shuffle(String command) {
//        m_tk = new StringTokenizer(command);
//        String text;
//
//
//        if (m_tk.countTokens() == 1) {
//            text = m_tk.nextToken().trim();
//
//            if (text.equalsIgnoreCase("shuffle")) {
//                m_game.shuffle();
//                return true;
//            }
//        }
//
//        return false;
//    }
//
//    private boolean exec_command_keyPhropecy(String command) {
//        ArrayList<Integer> order;
//
//
//        m_tk = new StringTokenizer(command);
//        String text;
//        String positions;
//
//
//        if (m_tk.countTokens() == 4) {
//            text = m_tk.nextToken();
//            text += " ";
//            text += m_tk.nextToken();
//            text += " ";
//            text += m_tk.nextToken();
//            text += " ";
//            text += m_tk.nextToken();
//
//            if (text.equalsIgnoreCase("get cards from deck")) {
//                ArrayList<Integer> arry = null;
//                m_game.get5TopCardsFromDeck();
//
//                showTempPile();
//
//                positions = m_consola.askString("Ordena da 1�� �� 4�� carta, sabendo que a que n��o ordena vai para o graveyard\n"
//                        + "(Utilize espa��os e numeros para indicar quais as cartas a serem ordenadas)\n-@>");
//
//                order = verifyPositions(positions);
//
//                if (order != null) {
//                    m_game.repositionCardsOnDeck(order);
//                    return true;
//                } else {
//                    return false;
//                }
//
//
//            }
//        }
//
//        return false;
//    }
//
//    private boolean exec_command_discardHand(String command) {
//        m_tk = new StringTokenizer(command);
//        String text;
//
//
//        if (m_tk.countTokens() == 2) {
//            text = m_tk.nextToken().trim();
//            text += " " + m_tk.nextToken().trim();
//
//            if (text.equalsIgnoreCase("discard hand")) {
//                m_game.discardHandNightmare();
//                return true;
//            }
//        }
//
//        return false;
//    }
//
//    private boolean exec_command_captureDoor(String command) {
//        m_tk = new StringTokenizer(command);
//        String text;
//
//
//        if (m_tk.countTokens() == 3) {
//            text = m_tk.nextToken().trim();
//            text += " " + m_tk.nextToken().trim();
//
//            if (text.equalsIgnoreCase("capture door")) {
//                
//
//                String pos = m_tk.nextToken().trim();
//
//                if (matchesInt(pos)) {
//                    if (m_game.captureDoor(Integer.parseInt(pos))) {
//                        return true;
//                    } 
//                } else {
//                    m_consola.writeTextNL("O parametro da pos nao e um inteiro");
//                    return true;
//                }
//
//
//            }
//        }
//
//        return false;
//    }
//
//    private boolean exec_command_discardDoor(String command) {
//        m_tk = new StringTokenizer(command);
//        String text;
//
//
//        if (m_tk.countTokens() == 2) {
//            text = m_tk.nextToken().trim();
//            text += " " + m_tk.nextToken().trim();
//
//            if (text.equalsIgnoreCase("discard door")) {
//                m_game.discardDoor();
//                return true;
//            }
//        }
//
//        return false;
//    }
//
//    private boolean exec_command_discoveryDoor(String command) {
//        m_tk = new StringTokenizer(command);
//        String text;
//
//
//        if (m_tk.countTokens() == 2) {
//            text = m_tk.nextToken().trim();
//            text += " " + m_tk.nextToken().trim();
//
//            if (text.equalsIgnoreCase("discover door")) {
//                if (m_game.discoverDoor()) {
//                    return true;
//                } else {
//                    m_consola.writeTextNL("Nao ha portas para essa cor");
//                    return true;
//                }
//
//            }
//        }
//
//        return false;
//    }
//
//    private boolean exec_cheat_show7Cards(String command) {
//        m_tk = new StringTokenizer(command);
//        String text;
//
//
//        if (m_tk.countTokens() == 3) {
//            text = m_tk.nextToken().trim();
//            text += " " + m_tk.nextToken().trim() + " " + m_tk.nextToken().trim();
//
//            if (text.equalsIgnoreCase("cheat show cards")) {
//                m_consola.writeTextNL(show7cardsFromDeck());
//                return true;
//            }
//        }
//
//        return false;
//
//
//
//    }
//
//    private boolean exec_cheat_addCardHand(String command) {
//        m_tk = new StringTokenizer(command);
//        String text;
//
//
//        if (m_tk.countTokens() == 4) {
//            text = m_tk.nextToken().trim();
//            text += " " + m_tk.nextToken().trim() + " " + m_tk.nextToken().trim();
//
//            if (text.equalsIgnoreCase("cheat add hand")) {
//
//
//                if (m_game.cheat_addCardtoHand(m_tk.nextToken().trim())) {
//                    return true;
//                } else {
//                    m_consola.writeTextNL("Nao foi encontrada uma carta com esse nome!");
//                    return true;
//                }
//
//            }
//        }
//
//        return false;
//
//    }
//
//    private boolean exec_cheat_addCardDeck(String command) {
//        m_tk = new StringTokenizer(command);
//        String text;
//
//
//        if (m_tk.countTokens() == 4) {
//            text = m_tk.nextToken().trim();
//            text += " " + m_tk.nextToken().trim() + " " + m_tk.nextToken().trim();
//
//            if (text.equalsIgnoreCase("cheat add deck")) {
//
//
//                if (m_game.cheat_addCardtoDeck(m_tk.nextToken().trim())) {
//                    return true;
//                } else {
//                    m_consola.writeTextNL("Nao foi encontrada uma carta com esse nome!");
//                    return true;
//                }
//
//            }
//        }
//
//        return false;
//    }
//
//    private boolean exec_cheat_addCardTable(String command) {
//        m_tk = new StringTokenizer(command);
//        String text;
//
//
//        if (m_tk.countTokens() == 4) {
//            text = m_tk.nextToken().trim();
//            text += " " + m_tk.nextToken().trim() + " " + m_tk.nextToken().trim();
//
//            if (text.equalsIgnoreCase("cheat add table")) {
//
//
//                if (m_game.cheat_addCardtoTable(m_tk.nextToken().trim())) {
//                    return true;
//                } else {
//                    m_consola.writeTextNL("Nao foi encontrada uma carta com esse nome!");
//                    return true;
//                }
//
//            }
//        }
//
//        return false;
//    }
//
//    private boolean exec_command_exit(String command) {
//        m_tk = new StringTokenizer(command);
//        String text;
//
//
//        if (m_tk.countTokens() == 1) {
//            text = m_tk.nextToken().trim();
//
//            if (text.equalsIgnoreCase("exit")) {
//                m_consola.writeTextNL("At�� �� pr��xima!\n");
//                System.exit(1);
//
//            }
//        }
//
//        return false;
//
//    }
//
//    /*
//     * M��todo privado que �� chamado aquando executamos o cheat de mostrar as 7 ultimas cartas do baralho
//     * 
//     * �� passado para um arraylist de cards as cartas do deck
//     * de seguida verificamos se o deck �� maior que zero
//     * Se Sim: igualamos o i ao numero de cartas contidas no deck menos 7 posi����es;
//     * Se o i for menor que 0, o i fica a 0;
//     * E enquanto o i for inferior ao tamanho do deck,
//     * escreve para a string os nomes das cartas
//     * 
//     * retorna uma a string com os nomes
//     */
//    private String show7cardsFromDeck() {
//        String text = "Deck: "; 
//        ArrayList<Card> deck = m_game.getDeck();
//
//
//        int i;
//
//
//
//        if (deck.size() > 0) {
//
//            i = deck.size() - 7;
//
//            if (i < 0) {
//                i = 0;
//            }
//
//            while (i < deck.size()) {
//                text += deck.get(i).getName() + "|";
//                i++;
//            }
//        } else {
//            return text + "No cards";
//        }
//
//        return text;
//
//
//    }
//
//    /*
//     * Fun����o de consulta para saber se o parametro neste caso uma string
//     * cont��m um inteiro
//     * devolve true se for um inteiro, sen��o devolve false;
//     */
//    private boolean matchesInt(String word) {
//        Pattern p = Pattern.compile("([0-9]*)");
//
//        Matcher m = p.matcher(word);
//
//        if (m.matches()) {
//            return true;
//        } else {
//            return false;
//        }
//    }
//
//    /*
//     * Fun����o que verifica se as posi����es (no caso da Phropecy) s��o inteiros
//     * Se os counts do tokenizer forem diferentes de 4 (ou seja precisamos de ordernar as 4 cartas, 
//     * sabendo que a ultima �� descartada)
//     * Retorna null;
//     * 
//     * Sen��o
//     * Enquanto existir tokens,
//     * Verificamos se o pos �� inteiro atrav��s do match
//     * Se for adicionamos a um array de inteiros
//     * Sen��o for um inteiro
//     * retorna null;
//     * 
//     * Continuando com a execu����o se for um inteiro, verificamos dos numeros de 1 a 5 qual deles �� que falta
//     * e adicionamos ao array
//     * Retornando o array no final
//     */
//    private ArrayList<Integer> verifyPositions(String positions) {
//        ArrayList<Integer> arry = new ArrayList<>();
//        Integer c;
//
//        m_tk = new StringTokenizer(positions);
//
//        if (m_tk.countTokens() != 4) {
//            return null;
//        }
//
//        while (m_tk.hasMoreTokens()) {
//            String pos = m_tk.nextToken().trim();
//
//            if (matchesInt(pos)) {
//                c = Integer.parseInt(pos);
//                arry.add(c);
//            } else {
//                m_consola.writeTextNL("Todas as posicoes tem que ser um numero");
//                return null;
//            }
//        }
//
//        for (int i = 1; i <= 5; i++) {
//            int count = 0;
//
//            for (Integer it : arry) {
//                if (i == it.intValue()) {
//                    count++;
//                }
//            }
//
//            if (count == 0) //Nao foi escolhida essa posi����o ent��o inserto no final
//            {
//                arry.add(i);
//            }
//        }
//
//        return arry;
//    }
//
//    /*
//     * M��todo que chama outros m��todos para mostrar as v��rias cartas
//     */
//    private void showCards() {
//        //showDeck();
//        showHand();
//        showTable();
//        showLimbo();
//        showGraveyard();
//        showDoorsPile();
//    }
//
//    /*
//     * M��todo que mostra as cartas existentes na tempPile
//     * Se existir size > 0, retorna uma string com os nomes
//     * Sen��o
//     * Retorna uma string com "No cards"
//     */
//    private void showTempPile() {
//        ArrayList<Card> temp = m_game.getTempPile();
//
//        String text = "TempPile: ";
//
//        if (temp.size() > 0) {
//            for (Card c : temp) {
//                text += c.getName() + "|";
//            }
//        } else {
//            text += "No cards";
//        }
//
//        m_consola.writeTextNL(text);
//
//
//
//    }
//
//    /*
//     * M��todo que mostra as cartas existentes na Table
//     * Se existir size > 0, retorna uma string com os nomes
//     * Sen��o
//     * Retorna uma string com "No cards"
//     */
//    private void showTable() {
//
//        ArrayList<Card> table = m_game.getTable();
//
//        String text = "Table: ";
//
//        if (table.size() > 0) {
//            for (Card c : table) {
//                text += c.getName() + "|";
//            }
//        } else {
//            text += "No cards";
//        }
//
//        m_consola.writeTextNL(text);
//    }
//
//    /*
//     * M��todo que mostra as cartas existentes no deck
//     * Se existir size > 0, retorna uma string com os nomes
//     * Sen��o
//     * Retorna uma string com "No cards"
//     */
//    private void showDeck() {
//
//        ArrayList<Card> deck = m_game.getDeck();
//
//        String text = "Deck: ";
//
//        if (deck.size() > 0) {
//            for (Card c : deck) {
//                text += c.getName() + "|";
//            }
//        } else {
//            text += "No cards";
//        }
//
//        m_consola.writeTextNL(text);
//
//    }
//
//    /*
//     * M��todo que mostra as cartas existentes na hand
//     * Se existir size > 0, retorna uma string com os nomes
//     * Sen��o
//     * Retorna uma string com "No cards"
//     */
//    private void showHand() {
//
//        ArrayList<Card> hand = m_game.getHand();
//
//        String text = "Hand: ";
//
//        if (hand.size() > 0) {
//            for (Card c : hand) {
//                text += c.getName() + "|";
//            }
//        } else {
//            text += "No cards";
//        }
//
//        m_consola.writeTextNL(text);
//
//    }
//
//    /*
//     * M��todo que mostra as cartas existentes no limbo
//     * Se existir size > 0, retorna uma string com os nomes
//     * Sen��o
//     * Retorna uma string com "No cards"
//     */
//    private void showLimbo() {
//        ArrayList<Card> limbo = m_game.getLimbo();
//
//        String text = "Limbo:  ";
//
//        if (limbo.size() > 0) {
//            for (Card c : limbo) {
//                text += c.getName() + "|";
//            }
//        } else {
//            text += "No cards";
//        }
//
//        m_consola.writeTextNL(text);
//
//    }
//
//    /*
//     * M��todo que mostra as cartas existentes no Graveyard
//     * Se existir size > 0, retorna uma string com os nomes
//     * Sen��o
//     * Retorna uma string com "No cards"
//     */
//    private void showGraveyard() {
//        ArrayList<Card> graveyard = m_game.getGraveyard();
//
//        String text = "Graveyard: ";
//
//        if (graveyard.size() > 0) {
//            for (Card c : graveyard) {
//                text += c.getName() + "|";
//            }
//        } else {
//            text += "No cards";
//        }
//
//        m_consola.writeTextNL(text);
//
//    }
//
//    /*
//     * M��todo que mostra as cartas existentes na doorsPile
//     * Se existir size > 0, retorna uma string com os nomes
//     * Sen��o
//     * Retorna uma string com "No cards"
//     */
//    private void showDoorsPile() {
//        ArrayList<Card> doors = m_game.getDoorsPile();
//
//        String text = "DoorsPile: ";
//
//        if (doors.size() > 0) {
//            for (Card c : doors) {
//                text += c.getName() + "|";
//            }
//        } else {
//            text += "No cards";
//        }
//
//        m_consola.writeTextNL(text);
//
//    }
}
